home *** CD-ROM | disk | FTP | other *** search
/ Freelog Special Freeware 31 / FreelogHS31.iso / ArgentCompta / Bankperfect / bp.exe / Scripts / Import QIF / import_qif.py < prev   
Text File  |  2007-03-25  |  15KB  |  364 lines

  1. #1.5
  2. import BP
  3.  
  4. d = {}
  5. ko = "└┴┬├─┼╞╟╚╔╩╦╠═╬╧╤╥╙╘╒╓┘┌█▄▌▀αßΓπΣσµτΦΘΩδ∞φε∩±≥≤⌠⌡÷∙·√ⁿ² ABCDEFGHIJKLMNOPQRSTUVWXYZ"
  6. ok = "aaaaaaaceeeeiiiinooooouuuuybaaaaaaaceeeeiiiinooooouuuuyyabcdefghijklmnopqrstuvwxyz"
  7. [d.setdefault(a, b) for a, b in zip(ko, ok)]
  8. PatternTable = "".join([d.get(chr(i), chr(i)) for i in range(256)])
  9.  
  10. CIndexes = {}
  11. CtgPatt = []
  12.  
  13. def Pattern(v):
  14.   return v.translate(PatternTable, " -.,;:/!?'_=")
  15.  
  16. def DoIndexCategs():
  17.   global CIndexes, CtgPatt
  18.   CIndexes = {}
  19.   for i, c in enumerate(BP.CategName):
  20.     CIndexes[i] = int(c[:c.find("=")])
  21.   CtgPatt = [Pattern(c) for c in BP.CategName]
  22.  
  23. DoIndexCategs()
  24. Acc = BP.AccountCurrent()
  25. l, b, a, cc = "TLabel", "TButton", ["akBottom", "akRight"], CreateComponent
  26. DtFmts = ["JMA", "MJA", "AMJ"]
  27. FDup = cc("TForm", None)
  28. FDup.SetProps(Width=400, Height=390, Position="poMainFormCenter", BorderStyle="bsSingle", BorderIcons=["biSystemMenu"], Caption="DΘtection de doublons")
  29. l0 = cc(l, FDup)
  30. l0.SetProps(Parent=FDup, Left=20, Top=20)
  31. l1 = cc(l, FDup)
  32. l1.SetProps(Parent=FDup, Left=20, Top=60, Caption="Ligne α insΘrer :")
  33. l2 = cc(l, FDup)
  34. l2.SetProps(Parent=FDup, Left=20, Top=190, Caption="Ligne existante :")
  35. l0.Font.Style = l1.Font.Style = l2.Font.Style = ["fsBold"]
  36. cc(l, FDup).SetProps(Parent=FDup, Left=40, Top=80, Caption="Date :")
  37. cc(l, FDup).SetProps(Parent=FDup, Left=40, Top=100, Caption="Mode :")
  38. cc(l, FDup).SetProps(Parent=FDup, Left=40, Top=120, Caption="Tiers :")
  39. cc(l, FDup).SetProps(Parent=FDup, Left=40, Top=140, Caption="DΘtails :")
  40. cc(l, FDup).SetProps(Parent=FDup, Left=40, Top=160, Caption="Montant :")
  41. cc(l, FDup).SetProps(Parent=FDup, Left=40, Top=210, Caption="Date :")
  42. cc(l, FDup).SetProps(Parent=FDup, Left=40, Top=230, Caption="Mode :")
  43. cc(l, FDup).SetProps(Parent=FDup, Left=40, Top=250, Caption="Tiers :")
  44. cc(l, FDup).SetProps(Parent=FDup, Left=40, Top=270, Caption="DΘtails :")
  45. cc(l, FDup).SetProps(Parent=FDup, Left=40, Top=290, Caption="Montant :")
  46. lD = cc(l, FDup)
  47. lD.SetProps(Parent=FDup, Left=120, Top=80)
  48. lM = cc(l, FDup)
  49. lM.SetProps(Parent=FDup, Left=120, Top=100)
  50. lT = cc(l, FDup)
  51. lT.SetProps(Parent=FDup, Left=120, Top=120)
  52. lI = cc(l, FDup)
  53. lI.SetProps(Parent=FDup, Left=120, Top=140)
  54. lA = cc(l, FDup)
  55. lA.SetProps(Parent=FDup, Left=120, Top=160)
  56. LD = cc(l, FDup)
  57. LD.SetProps(Parent=FDup, Left=120, Top=210)
  58. LM = cc(l, FDup)
  59. LM.SetProps(Parent=FDup, Left=120, Top=230)
  60. LT = cc(l, FDup)
  61. LT.SetProps(Parent=FDup, Left=120, Top=250)
  62. LI = cc(l, FDup)
  63. LI.SetProps(Parent=FDup, Left=120, Top=270)
  64. LA = cc(l, FDup)
  65. LA.SetProps(Parent=FDup, Left=120, Top=290)
  66. lD.Font.Color = lM.Font.Color = lT.Font.Color = lI.Font.Color = lA.Font.Color = LD.Font.Color = LM.Font.Color = LT.Font.Color = LI.Font.Color = LA.Font.Color = 0x00CC0000
  67. cc(b, FDup).SetProps(Parent=FDup, Left=40, Top=320, Width=75, Height=25, Caption="Oui", ModalResult=6)
  68. cc(b, FDup).SetProps(Parent=FDup, Left=120, Top=320, Width=75, Height=25, Caption="Non", ModalResult=7)
  69. cc(b, FDup).SetProps(Parent=FDup, Left=200, Top=320, Width=75, Height=25, Caption="Toutes", ModalResult=10)
  70. cc(b, FDup).SetProps(Parent=FDup, Left=280, Top=320, Width=75, Height=25, Caption="Aucune", ModalResult=9)
  71.  
  72. def CheckPos(Sender):
  73.   CCtgs.Top = F0.Height - 70
  74.  
  75. F0 = cc("TForm", None)
  76. F0.SetProps(Position = "poMainFormCenter", Width=600, Height=320, Caption = "ParamΦtres de l'import", OnShow=CheckPos)
  77. F0.Constraints.MinWidth = 600
  78. cc(l, F0).SetProps(Parent=F0, Left=16, Top=20, Caption="Sens de la date :")
  79. cc(l, F0).SetProps(Parent=F0, Left=160, Top=20, Caption="Doublons :")
  80. cc(l, F0).SetProps(Parent=F0, Left=276, Top=20, Caption="Contenu du fichier :")
  81. CBDate = cc("TComboBox", F0)
  82. CBDate.SetProps(Parent=F0, Left=16, Top=39, Width=93, Style="csDropDownList")
  83. CBDate.Items.Text = "\n".join(DtFmts)
  84. CBDate.ItemIndex = 0
  85. CBDup = cc("TComboBox", F0)
  86. CBDup.SetProps(Parent=F0, Left=160, Top=39, Width=100, Style="csDropDownList")
  87. CBDup.Items.Text = "Tout accepter\nTout refuser\nDemander"
  88. CBDup.ItemIndex = 2
  89. Memo = cc("TMemo", F0)
  90. Memo.SetProps(Parent=F0, Left=276, Top=40, Width=293, Height=89, WordWrap=1, Anchors=a+["akTop","akLeft"])
  91. CCtgs = cc("TCheckBox", F0)
  92. CCtgs.SetProps(Parent=F0, Left=16, Top=300, Width=213, Caption="CrΘer les catΘgories manquantes", Anchors=["akLeft", "akBottom"])
  93. BKO = cc(b, F0)
  94. BKO.SetProps(Parent=F0, Left=415, Top=300, Width=75, Height=25, Caption="Annuler", ModalResult=2, Cancel=1, Anchors=a)
  95. BOK = cc(b, F0)
  96. BOK.SetProps(Parent=F0, Left=495, Top=300, Width=75, Height=25, Caption="Suivant >>", ModalResult=1, Default=1, Anchors=a)
  97.  
  98. FF = cc("TForm", None)
  99. FF.SetProps(Width=640, Height=450, Position="poMainFormCenter", BorderStyle="bsSingle", BorderIcons=["biSystemMenu"], Caption="RΘsultat de l'import")
  100. cc(b, FF).SetProps(Parent=FF, Left=270, Top=370, Width=100, Height=25, Caption="Fermer", ModalResult=1, Cancel=1, Default=1)
  101. MRes = cc("TMemo", FF)
  102. MRes.SetProps(Parent=FF, Left=30, Top=30, Width=580, Height=350, Anchors=["akTop","akLeft", "akRight", "akBottom"], WordWrap=0, Readonly=1)
  103.  
  104. FF.Font.Name = F0.Font.Name = FDup.Font.Name = "Tahoma"
  105.  
  106. def GetCtg(s):
  107.   if s.strip() == "": return -1
  108.   t = Pattern(s)
  109.   if t.strip() == "": return -1
  110.   if t in CtgPatt: return CIndexes.get(CtgPatt.index(t), -1)
  111.  
  112.   for i in range(len(CtgPatt)):
  113.     c = CtgPatt[i]
  114.     if t in c or c in t: return CIndexes.get(i, -1)
  115.  
  116.   if CCtgs.Checked:
  117.     BP.CategAdd(s, 0)
  118.     DoIndexCategs()
  119.     return CIndexes.get(BP.CategCount() - 1, -1)
  120.   return -1
  121.  
  122. def getmode(s, sign):
  123.   s = s.strip()
  124.   if s != "":
  125.     if sign == -1 and s.isdigit(): return "Chq %s" %s
  126.  
  127.     v = Pattern(s)
  128.     if sign == 1: fmodes = {"Versement": ["vers", "esp"], "DΘp⌠t de chΦque": ["rem", "dep", "ch"], "Virement reτu": ["vir", "vrm", "vrt"]}
  129.     else: fmodes = {"Carte": ["fac", "cb", "car"], "Retrait DAB": ["ret", "dab", "distrib", "automat"], "ChΦque Θmis": ["ch"], "PrΘlΦvement": ["pr"], "Virement Θmis": ["vir", "vrm", "vrt"], "TIP": ["tip"]}
  130.  
  131.     for m in fmodes.keys():
  132.       fpatterns = fmodes[m]
  133.       for fpattern in fpatterns:
  134.         if v.find(fpattern) == 0:
  135.           if m == "ChΦque Θmis":
  136.             v = s.split(" ")[-1].split(".")[-1].split("░")[-1].split("Q")[-1].split("E")[-1].split("H")[-1]
  137.             if v.isdigit(): return "Chq %s" %v
  138.           return m
  139.   if sign == 1: return "Virement reτu"
  140.   return "PrΘlΦvement"
  141.  
  142. def getprefixes(L):
  143.   d = {}
  144.   for l in L:
  145.     if len(l) > 0 and l[0] in "ABCDEFGHIJKLMNOPQRSTUVWXYZ":
  146.       d[l[0]] = 1
  147.   r = d.keys()
  148.   r.sort()
  149.   return r
  150.  
  151. def AddCombos(prefixes):
  152.   c = "\n".join(["--------", "Date", "Mode", "Tiers", "DΘtails", "CatΘgorie", "Montant"])
  153.   f = []
  154.   for i, p in enumerate(prefixes):
  155.     top = 84 + i * 26
  156.     cc("TLabel", F0).SetProps(Parent=F0, Left=16, Top=top+4, Caption="La lettre %s prΘcΦde le champ" %p)
  157.     cb = cc("TComboBox", F0)
  158.     cb.SetProps(Parent=F0, Left=160, Top=top, Width=100, Style="csDropDownList")
  159.     cb.Items.Text = c
  160.     cb.ItemIndex = "DNPMLT".find(p) + 1
  161.     f.append(cb)
  162.   return f
  163.  
  164. def strtodate(d):
  165.   seps = "/-' .;"
  166.   d = d.replace("-", "/").replace(".", "/").replace("'", "/").replace(" ", "").split("/")
  167.   if len(d) != 3 or not "".join(d).isdigit(): return None
  168.   d = [int(d[0]), int(d[1]), int(d[2])]
  169.   if DtFmt == "JMA": return (d[2], d[1], d[0])
  170.   elif DtFmt == "MJA": return (d[2], d[0], d[1])
  171.   elif DtFmt == "AMJ": return (d[0], d[1], d[2])
  172.   elif DtFmt == "AJM": return (d[0], d[2], d[1])
  173.   else: return None
  174.  
  175. def strtofloat(s):
  176.   s = s.replace("$", "").replace(" ", "").replace("Ç", "").replace("F", "").replace(",", ".")
  177.   if "." in s:
  178.     l = s.split(".")
  179.     s = "%s.%s" %( "".join(l[:-1]), l[-1] )
  180.   try:
  181.     f = float(s)
  182.   except:
  183.     return None
  184.   return f
  185.  
  186. def linestodic(lines, mapping):
  187.   fields = ["Date", "Mode", "Tiers", "DΘtails", "CatΘgorie", "Montant"]
  188.   result = {}
  189.   sgn = 0
  190.   for line in lines:
  191.     i = mapping[line[0]]
  192.     if i > 0:
  193.       field = fields[i - 1]
  194.       value = line[1:]
  195.       if field == "Date":
  196.         value = strtodate(value)
  197.         if value is None: return None
  198.       elif field == "CatΘgorie": value = GetCtg(value)
  199.       elif field == "Montant":
  200.         value = strtofloat(value)
  201.         if value == None: return None
  202.         if value > 0: sgn = 1
  203.         elif value < 0: sgn = -1
  204.       result[field] = value
  205.   try:
  206.     if sgn != 0: result["Mode"] = getmode(result.get("Mode", ""), sgn)
  207.   except:
  208.     pass
  209.   return result
  210.  
  211. def divide(lines, mapping):
  212.   res = []
  213.   MinDate = (3000, 12, 31)
  214.   rep = {"OpΘrations importΘes" : [], "Dates incorrectes" : [], "Montants incorrects" : [], "Enregistrements incorrects" : [], "Lignes refusΘes" : [], "Doublons" : []}
  215.   while lines.count("^") > 0:
  216.     i = lines.index("^")
  217.     r = linestodic(lines[:i], mapping)
  218.     if r != None:
  219.       if not r.has_key("Date"): rep["Dates incorrectes"].append(",  ".join(lines[:i]))
  220.       elif not r.has_key("Montant"): rep["Montants incorrects"].append(",  ".join(lines[:i]))
  221.       else:
  222.         y, m, d = r["Date"]
  223.         if y < 100: y += 2000
  224.         r["Date"] = (y, m, d)
  225.         if (y, m, d) < MinDate: MinDate = (y, m, d)
  226.         res.append(r)
  227.     else: rep["Enregistrements incorrects"].append(",  ".join(lines[:i]))
  228.     del lines[:i + 1]
  229.   return res, rep, MinDate
  230.  
  231. def FlatCheck(m, t, i):
  232.   if m == "ChΦque Θmis" and i != "":
  233.     num = t.split("░")[-1].split(" ")[-1]
  234.     if num.isdigit(): m = "Chq %s" %num
  235.     else:
  236.       num = i.split("░")[-1].split(" ")[-1]
  237.       if num.isdigit(): m = "Chq %s" %num
  238.  
  239.   if m.find("Chq ") == 0:
  240.     if i == "": i = "n░%s" %(m[4:])
  241.     else: i = "n░%s %s" %(m[4:], i)
  242.     m = "ChΦque Θmis"
  243.     
  244.   return m, t, i
  245.  
  246. def ReportErrors(R):
  247.   ok = 0
  248.   ko = 0
  249.   L = []
  250.   for key in R.keys():
  251.     l = R[key]
  252.     num = len(l)
  253.     if num == 0: continue
  254.     if key == "OpΘrations importΘes": ok += num
  255.     else: ko += num
  256.     l = ["  %s" %s for s in l]
  257.     L.append("%s (%d) :\r\n\r\n%s" %(key, num, "\r\n".join(l)))
  258.  
  259.   T = ok + ko
  260.   if T == 0:
  261.     s = "Il n'y a aucune ligne α importer depuis le fichier"
  262.   else:
  263.     if ko == 0:
  264.       if T == 1: s = "L'opΘration contenue dans le fichier QIF a ΘtΘ importΘe sans erreurs"
  265.       else: s = "Les %d opΘrations contenues dans le fichier QIF ont ΘtΘ importΘes sans erreurs" %T
  266.     elif ok == 0: s = "Aucune ligne n'a pu Ωtre importΘe"
  267.     else:
  268.       if ok == 1: s = "Une opΘration sur %d a ΘtΘ importΘe" %(T)
  269.       else: s = "%d opΘrations sur %d ont ΘtΘ importΘes" %(ok, T)
  270.  
  271.     s = "%s\r\n\r\n%s" %(s, "\r\n\r\n".join(L))
  272.   return s
  273.  
  274. def IsDate(t):
  275.   try:
  276.     y, m, d = t
  277.     if (m == 2) and (y % 4 == 0) and ( (y % 100 != 0) or (y % 400 == 0) ): Max = 29
  278.     else: Max = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31][m - 1]
  279.     return m > 0 and m < 13 and d > 0 and d <= Max
  280.   except:
  281.     return 0
  282.  
  283. def FormatLine(dic):
  284.   s = []
  285.   for key in dic:
  286.     v = dic[key]
  287.     if key == "Date": v = datetostr(v)
  288.     s.append("%s : %s" %(key, v))
  289.     s.sort()
  290.   return ",  ".join(s)
  291.  
  292. def datetostr(d):
  293.   y, m, d = d
  294.   if y < 100: y += 2000
  295.   return "%02d/%02d/%04d" %(d, m, y)
  296.  
  297. def TestDup(N, T, Rep, ask, Lines, Light, R, d, m, v):
  298.   if ask == 0: res = "ok", ask
  299.   elif not (d, m, v) in Light: res = "ok", ask
  300.   elif ask == 1: res = "ko", ask
  301.   else:
  302.     i = Light.index((d, m, v))
  303.     l = Lines[i]
  304.     lD.Caption, lM.Caption, lT.Caption, lI.Caption, lA.Caption = datetostr(R[0]), R[1], R[2], R[3], R[4]
  305.     LD.Caption, LM.Caption, LT.Caption, LI.Caption, LA.Caption = datetostr(l[0]), l[1], l[3], l[4], l[2]
  306.     l0.Caption = "La ligne %d/%d ressemble α une ligne existante.\nSouhaitez-vous l'insΘrer ?" %(N, T)
  307.     i = FDup.ShowModal()
  308.     res = {2: ("ko", ask), 6: ("ok", ask), 10: ("ok", 0), 7: ("ko", ask), 9: ("ko", 1)}[i]
  309.  
  310.   if res[0] == "ko": Rep["Doublons"].append(line)
  311.   return res
  312.  
  313. def simplecheck(s):
  314.   return [s, "ChΦque Θmis"][s.find("Chq") == 0]
  315.  
  316. def GetLines(From):
  317.   l1 = zip(BP.OperationDate[Acc], BP.OperationMode[Acc], BP.OperationAmount[Acc], BP.Operationthirdparty[Acc], BP.OperationDetails[Acc])
  318.   l1 = [((int(d[6:10]), int(d[3:5]), int(d[0:2])), m, v, w, i) for (d, m, v, w, i) in l1 if (int(d[6:10]), int(d[3:5]), int(d[0:2])) >= From]
  319.   l2 = [(l[0], simplecheck(l[1]), l[2]) for l in l1]
  320.   return l1, l2
  321.  
  322.  
  323.  
  324. QIFFile = BP.OpenDialog("Choisissez le fichier α importer", "\\", ".qif", "Quicken Interchange Format (*.QIF)|*.qif")
  325. if QIFFile != "":
  326.   f = open(QIFFile).readlines()
  327.   f = [l.replace("\n", "").strip() for l in f if len(l) > 0 and l[0] in "ABCDEFGHIJKLMNOPQRSTUVWXYZ^"]
  328.   prefixes = getprefixes(f)
  329.   if len(prefixes) < 3: BP.MsgBox("Le fichier n'est pas un fichier QIF correct", 0)
  330.   else:
  331.     BP.AccountRefreshScreen()
  332.     h = 160 + 26 * len(prefixes)
  333.     Combos = AddCombos(prefixes)
  334.     Memo.Height, Memo.Lines.Text = h - 121, "\n".join(f[:50])
  335.     CCtgs.Top = BKO.Top = BOK.Top = h - 69
  336.     F0.Height = F0.Constraints.MinHeight = h
  337.     Memo.Height = h - 120
  338.     BOK.Top = h - 70
  339.     BKO.Top = h - 70
  340.     if F0.ShowModal() == 1:
  341.       dupl, DtFmt = CBDup.ItemIndex, DtFmts[CBDate.ItemIndex]
  342.       mapping = dict([(p, Combos[i].ItemIndex) for i, p in enumerate(prefixes)])
  343.       operations, report, MinDate = divide(f, mapping)
  344.       CurrLines, LinesLight = GetLines(MinDate)
  345.       i, num_ok, count_op = 0, 0, len(operations)
  346.       for op in operations:
  347.         line, i = FormatLine(op), i + 1
  348.         date, mode, tier, info, catg, mont = op.get("Date", ""), op.get("Mode", ""), op.get("Tiers", ""), op.get("DΘtails", ""), op.get("CatΘgorie", ""), op.get("Montant", "")
  349.         if not IsDate(date): report["Dates incorrectes"].append(line)
  350.         elif mont == "" or abs(mont) < 0.0001: report["Montants incorrects"].append(line)
  351.         else:
  352.           InsDup, dupl = TestDup(i, count_op, report, dupl, CurrLines, LinesLight, (date, mode, tier, info, mont), date, simplecheck(mode), mont)
  353.           if InsDup == "ko": continue
  354.           if catg == "": catg = -1
  355.           mode, tier, info = FlatCheck(mode, tier, info)
  356.           count1, date = BP.OperationCount[Acc], datetostr(date)
  357.           BP.LineAdd(Acc, date, mode, tier, info, catg, mont, 0)
  358.           count2 = BP.OperationCount[Acc]
  359.           if count2 == count1: report["Lignes refusΘes"].append(line)
  360.           else: report["OpΘrations importΘes"].append(line)
  361.  
  362.       BP.AccountRefreshScreen()
  363.       MRes.Lines.Text = ReportErrors(report)
  364.       FF.ShowModal()